<?php

class COBWEB{
	var $svr = null;
        var $obj = null;
        var $MAXH = 2;
	function __construct(){
              $this->svr = array('0'=>'lafe1.search.cnb.yahoo.com', '1'=>'lafe2.search.cnb.yahoo.com');   
              $this->obj[0] = null;
              $this->obj[1] = null;
			  //  $this->connect();
	} 
		function prepare_obj($idx ){
			if(!is_object($this->obj[$idx] ))
			{
				$this->obj[$idx] = new Memcache;
				@$this->obj[$idx]->connect( $this->svr[$idx], 5080);
				echo "connect to ".$this->svr[$idx]."\n";
			}
		} 

	function failover($idx ){
                  $idx= ($idx + 1) % $this->MAXH;
                  return $idx;
	} 

	function __destruct() {
		for($i = 0; $i < $this->MAXH; $i++)
		{
			if(is_object($this->obj[$i])){
				@$this->obj[$i]->close();
				unset($this->obj[$i]);
			}
		} 
	}

	function Hash($str) 
	{
		$hash = abs(crc32($str));
		return $hash % $this->MAXH;
	}

	function read_func($hstr,  $func,  $kv = array()){
                $idx = $this->Hash($hstr) % $this->MAXH;
		$args = array($func );
		foreach($kv as $k=>$v)
			array_push($args, $v);
		array_push($args, "BIND-RESULT");
       $this->prepare_obj($idx);
		$ret = @$this->obj[$idx]->get($args);
		if($ret == false)
		{
			$idx = $this->failover($idx);
			$this->prepare_obj($idx);
			$ret = @$this->obj[$idx]->get($args);
		}
		if(!isset($ret['BIND-RESULT']))
			return false;
		return $ret['BIND-RESULT'];  //this->binary_parser($ret['BIND-RESULT']);
	}


	function reset( $user, $rebuild = false){
		$idx =  $this->Hash($user);
                $bRemote = 0;
                if($rebuild )
                     $bRemote = 1;
		$args = array("reset", $user, "$bRemote", "BIND-RESULT" );
		$this->prepare_obj($idx);
		$ret = @$this->obj[$idx]->get($args);
		if(isset($ret['BIND-RESULT']) && strcmp($ret['BIND-RESULT'], "OK") == 0)
			return true;
		return false;
	}
	function relation( $user1, $user2, $limit = 100, $offset = 0 ){
                $response = $this->read_func($user1, "relation", array($user1, $user2, $limit, $offset));  
		$arr = array();
		if(isset($response{3}))
		{
			$sub = substr($response, 0, 4);
			$unpacked = unpack('I',$sub);
			if(!isset($unpacked['1']))
                             return false;	
			$depth =  $arr['__depth__'] = $unpacked['1'];
			if($unpacked['1'] == 0 )
				return $arr;
		        	
			$idx = 4;
			$sub = substr($response, $idx , 4);
			if(!isset($sub{3}))
			{
				error_log("get depth data error!");
				return false;
			}
                        $idx += 4;
			$unpacked = unpack('I',$sub);
                    	$items = $unpacked['1'];
				//echo "items = "; var_dump($unpacked);
				// $direct = $response[$idx];
				// $idx += 1;
			for($j = 0; $j <$items ; $j++)
			{
				$subarr = array();
				for($i=0; $i<$depth; $i++)
				{
					$str = substr($response, $idx, 4);
					if(!isset($str{3})){
						error_log("get one line friends data error");
						return false;
					}

					$unpacked = unpack('Iint', $str);
					$idx += 4;
					$subarr[$i] = substr($response, $idx, $unpacked['int']);
					$idx += $unpacked['int'];
				}
				if(sizeof($subarr) > 0)
					$arr[$j] = $subarr;
			}
			if(sizeof($arr) < $items)
				return false;
		}
		else
			return false; //echo "return error!";
		return $arr;
	}
	function information( $users){
		$idxs = '';
		if(is_array($users))
		{
			foreach($users as $u)
			{
				$idxs = $u;
				break;
			}
		}
		else
			$idxs = $users;

		$idx = $this->Hash($idxs);
		$this->prepare_obj($idx);
		$rets = $this->obj[$idx]->get($users);
		if($rets == false)
		{
			$idx = $this->failover($idx);
			$this->prepare_obj($idx);
			$rets = @$this->obj[$idx]->get($users);
		}     

		$arr = array();
		if(is_array($rets))
		{
                   foreach($rets as $ret)
		   {
                           $idx = 0;
			   if(!isset($ret{3})){
				   error_log("get user type error");
				   return false;
			   }
			   $str = substr($ret , $idx, 4);
			   $unpacked = unpack('Iint', $str);
                           $idx += 4;
                           $name = substr($ret, $idx, $unpacked['int']); 
                           $idx += $unpacked['int'];

			   if(!isset($ret{$idx+3})){
				   error_log("get user type error");
				   return false;
			   }
			   $str = substr($ret , $idx, 4);
			   $unpacked = unpack('Iint', $str);
			   $idx += 4;
			   $value = substr($ret, $idx, $unpacked['int']); 
			   $idx += $unpacked['int'];
        
			   if(!isset($ret{$idx+3})){
				   error_log("get user type error");
				   return false;
			   }
			   $str = substr($ret , $idx, 4);
			   $unpacked = unpack('Iint', $str);
	                   $num = $unpacked['int']; 
                           $arr[$name] = array('__value__'=>$value, '__num__'=>$num);
                   }   
		}
		else
			return false; //echo "return error!";
		return $arr;
	}

	function friends( $user, $limit = 10, $offset = 0){
		$response = $this->read_func($user, "friends", array($user, $limit, $offset));
		if(isset($response{7}))
		{
			//echo "read = "; var_dump($response);
			$idx = 0;
			$sub = substr($response, $idx , 8);
			$unpacked = unpack('I2',$sub);
			//echo "counts = "; var_dump($unpacked);
			$idx += 8;
                        $arr['__counts__'] = $unpacked['2'];
                        $arr['__total__'] = $unpacked['1'];
			$counts = $unpacked['2'];
			if($counts == 0)
				return $arr;
			for($j = 0; $j<$counts ; $j++)
			{ 
				/* ulen + uname  */
				$str = substr($response, $idx, 4);
				if(!isset($str{3})){
					error_log("get firends name length data error");
					return false;
				}
				$unpacked = unpack('Iint', $str);
				$idx += 4;
				$uname = substr($response, $idx, $unpacked['int']);
				$idx += $unpacked['int'];
				/* vlen + value */
				$str = substr($response, $idx, 4);
				if(!isset($str{3})){
					error_log("get firends value length data error");
					return false;
				}
				$unpacked = unpack('Iint', $str);
				$idx += 4;
				if($unpacked['int'] > 0)
					$value = substr($response, $idx, $unpacked['int']);
				else
					$value = "";
				$idx += $unpacked['int'];
				/* type  */ 
				$str = substr($response, $idx, 4);
				if(!isset($str{3})){
					error_log("get user type error");
					return false;
				}
				$unpacked = unpack('Iint', $str);
				$idx += 4;
				$arr[$uname] = array('_value'=>$value, '_num'=>$unpacked['int']);
			}
			if(sizeof($arr) < $counts)
				return false;
		}
		else
			return false; //echo "return error!";
		return $arr;
	}

	function type_friends( $user, $type, $limit = 100, $offset = 0 ){
		$response = $this->read_func($user, "tfriends", array($user, $type, $limit, $offset));
		$arr = array();
		if(isset($response{7}))
		{
			$sub = substr($response, 0, 8);
			$unpacked = unpack('I2',$sub);
			if(isset($unpacked['1']) && isset($unpacked['2']))
			{
 
                                $arr['__total__'] =$unpacked['1'];
                                $arr['__counts__'] =$unpacked['2'];
				//echo "read = "; var_dump($response);
				$idx = 8;
				$counts = $unpacked['2'];
				if($counts == 0)
					return $arr;
				for($j = 0; $j<$counts ; $j++)
				{ 
					/* ulen + uname  */
					$str = substr($response, $idx, 4);
					if(!isset($str{3})){
						error_log("get firends name length data error");
						return false;
					}
					$unpacked = unpack('Iint', $str);
					$idx += 4;
					$uname = substr($response, $idx, $unpacked['int']);
					$idx += $unpacked['int'];
					/* vlen + value */
					$str = substr($response, $idx, 4);
					if(!isset($str{3})){
						error_log("get firends value length data error");
						return false;
					}
					$unpacked = unpack('Iint', $str);
					$idx += 4;
					if($unpacked['int'] > 0)
						$value = substr($response, $idx, $unpacked['int']);
					else
						$value = "";
					$idx += $unpacked['int'];
					/* type  */ 
					$arr[$uname] = array('__value__'=>$value, '__num__'=>$type);
				}
				if(sizeof($arr) < $counts)
					return false;
			}
		}
		else
			return false; //echo "return error!";
		return $arr;
	}

	function status($idx ){
		$idx = $idx % 2;
		$this->prepare_obj($idx);
		return  @$this->obj[$idx]->getStats(); // getExtendedStats();  
	}

	function configure($idx, $key, $val){
		$idx = $idx % 2;
		$args = array("stats", $key, $val, "BIND-RESULT");
		$this->prepare_obj($idx);
		$ret = @$this->obj[$idx]->get($args);
		if(!isset($ret['BIND-RESULT']))
			return false;
		$response = $ret['BIND-RESULT'];  
		return $response;
	}	

}
/*
$obj = new COBWEB();
$f = $obj->configure(1, "returnmax","200");
$frs =  $obj->status(1);
var_dump($frs);
//$frs =  $obj->relation("lengss","lengsh" );
//$frs =  $obj->friends("lengsh", 1 , 0);
//$frs =  $obj->type_friends("lengsh", 1 , 100, 0);
$frs =  $obj->information(array("1973","1","2","3"));

var_dump($frs);
//echo sizeof($frs);
*/
?>
